home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Night Owl 6
/
Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso
/
001a
/
cscom.zip
/
CSCOM.8
next >
Wrap
Text File
|
1991-10-09
|
31KB
|
1,502 lines
;CSCOM is a modem communication program for calling CompuServe and
;downloading a file using CompuServe's B+ protocol with an IBM
;compatible computer. I'm releasing CSCOM.COM and CSCOM.8 (the
;8086 assembly language source code file) to the Public Domain.
;It isn't as complete as it could be, but it's free. Feel free
;to improve on it.
;The weak areas are in the B+ protocol downloading routines. My
;source of information for the B+ protocol was BPLUS.DOC, which was
;the original documentation for the protocol, by Russ Ranshaw. It's a
;very impressive document, but it's ambiguous/vague/incomplete in
;some areas. I learned a lot by trial and error, but I didn't learn
;everything I wanted to. And my knowledge of Pascal didn't help much
;with the source code by Russ Ranshaw called BPLUS.PAS.
;o You can't exit the program while the download is in progress.
;o You can only download, not upload.
;o I'm not sure all possible errors are covered.
;o The download might be made to go a little faster.
;o The file to be downloaded must fit in memory beginning 64K above CSCOM.
;CSCOM was written using the ShareWare assembler, A86, which I highly
;recommend, in Oct, 1991.
;Doug Cox
;140 Monroe Dr.
;Palo Alto, Ca. 94306
;(415) 949-0624
;CompuServe ID# 70224,22
JMP MAIN
SCREENSEG DW ? ;SCREEN SEGMENT
NEXTSEG DW ? ;TO HOLD NEXT SEGMENT ADDRESS
ATTRIB DB 7 ;SCREEN COLOR ATTRIBUTE
BOXATTRIB DB 017
CURATTRIB DB 067
CFG DB 'CSCOM.CFG',0 ;HOLDS PHONE NUM, USER ID, & PASSWORD
HANDLE DW ?
CURLINELOC DW 361
CUROW DB 25,3,4,5,6,7 ;CURSOR ROWS
CUROWPTR DW OFFSET CUROW
ROWCOL LABEL WORD
COL DB 0
ROW DB 0
HUNDRED DW 100
TEMPSTORAGE DW ?
FLAGBYTE DB ? ;USED AS A FLAG AND FOR INT 015
CALLMENU:
DB '┌────────────Call CompuServe─────────────┐'
DB '│ Move cursor here & press Enter to call │'
DB '│ Phone Number: *70-415-949-0624 │'
DB '│ User ID: 70224,22 │'
DB '│ Password: │'
DB '│ Modem Speed: 2400 │'
DB '│ Comm Port: 1 │'
DB '└───────────Press ESC to Exit────────────┘'
COMPORT DB '1'
INIT DB 'ATE1Q0V1X4&C1&D2',0D,0 ;INITIALIZE MODEM
DW 3 ;LENGTH OF FOLLOWING STRING
OK DB 'OK',0D,0
CALLING DB 'Calling CompuServe$'
PHONENO DB 'ATDT'
PHONE2 DB 22 DUP('1')
DW 12
CONNECT DB 'CONNECT '
SPEED DB '2400'
SENDCR DB 0D,0
DW 11
HOST DB 'Host Name: '
SENDHOST DB 'CIS',0D,0
DW 9
USER DB 'User ID: '
SENDUSER DB 22 DUP('0')
DW 10
PASSWORD DB 'Password: '
SENDPASS DB 22 DUP('X')
DW 1
EXCLAIM DB '!'
TR_BUFFER DW ? ;UART PORT ADDRESS
INT_ENABLE DW ? ;+1
INT_IDENT DW ? ;+2
LINE_CONTROL DW ? ;+3
MODEM_CONTROL DW ? ;+4
LINE_STATUS DW ? ;+5
MODEM_STATUS DW ? ;+6
COMM_INT_STA DB ? ;COMMUNICATIONS INTERRUPT STATUS
INTOFF DW ? ;TO HOLD DEFAULT COMM INTERRUPT VECTOR
INTSEG DW ?
IN_BUFF_HEAD DW ?
IN_BUFF_TAIL DW ?
IN_BUFF_BEGIN DW ?
IN_BUFF_END DW ?
OUT_BUFF_HEAD DW ?
OUT_BUFF_TAIL DW ?
OUT_BUFF_BEGIN DW ?
OUT_BUFF_END DW ?
MAIN:
MOV AX,03D02 ;FUNCTION TO OPEN FILE FOR READ/WRITE
MOV DX,OFFSET CFG
INT 021
JNC GOTFILE ;IF FILE OPENED
MOV FLAGBYTE,0 ;NO .CFG FILE
JMP SHORT NOFILE
GOTFILE:
MOV FLAGBYTE,1 ;IF .CFG FILE EXISTS
MOV HANDLE,AX
MOV BX,AX
MOV AH,03F ;FUNCTION TO READ FILE
MOV CX,110 ;NUMBER OF BYTES
MOV DX,OFFSET BUF ;WHERE TO PUT FILE
INT 021
MOV AX,04200 ;FUNCTION TO MOVE FILE POINTER TO BEGINNING OF FILE
SUB CX,CX
SUB DX,DX
INT 021
MOV SI,OFFSET BUF
MOV DX,OFFSET CALLMENU
ADD DX,61
MOV BX,5
L0:
ADD DX,42
MOV DI,DX
MOV CX,22
REP MOVSB
DEC BX
JNZ L0
CALL BUF2MEM ;MOV BUF DATA TO PHONE2, ETC
NOFILE:
MOV AH,0F ;FUNCTION TO GET CURRENT DISPLAY MODE
INT 010
MOV SCREENSEG,0B800
CMP AL,7
JNE >L1 ;IF NOT MONO MODE
MOV SCREENSEG,0B000
MOV BOXATTRIB,7
MOV CURATTRIB,070
L1:
MOV AX,CS
ADD AX,01000
MOV NEXTSEG,AX ;FOR DOWNLOADED DATA
DRAWBOX:
CALL CLRSCRN
MOV ES,SCREENSEG
MOV SI,OFFSET CALLMENU
MOV AL,BOXATTRIB
MOV DX,198 ;SCREEN OFFSET
MOV BX,8 ;ROWS
L1:
MOV DI,DX
MOV CX,42 ;COLS
L2:
MOVSB
STOSB
LOOP L2
ADD DX,160
DEC BX
JNZ L1
PREADKBD:
CALL MAKECURLINE
MOV BX,CUROWPTR
MOV AL,[BX]
MOV ROW,AL
MOV COL,38 ;BEGINNING OF INPUT
PREAD2:
CALL MOVCUR
READKBD:
MOV AH,0
INT 016
CMP AX,05000 ;DOWN ARROW
JNE >L1
GODOWN:
CMP CURLINELOC,1161
JE READKBD ;IF AT BOTTOM
MOV AL,BOXATTRIB
CALL CURLINE ;CLEAR CURSOR LINE
ADD CURLINELOC,160
INC CUROWPTR
JMP PREADKBD
L1:
CMP AX,04800 ;UP ARROW
JNE >L2
CMP CURLINELOC,361
JE READKBD ;IF AT TOP
MOV AL,BOXATTRIB
CALL CURLINE
SUB CURLINELOC,160
DEC CUROWPTR
JMP PREADKBD
L2:
CMP AX,04B00 ;LEFT ARROW
JNE >L3
CMP COL,38
JE READKBD
DEC COL
JMP SHORT PREAD2
L3:
CMP AX,04D00 ;RIGHT ARROW
JNE >L4
CMP COL,59
JE READKBD
INC COL
JMP SHORT PREAD2
L4:
CMP AL,0D ;ENTER
JNE >L5
CMP CURLINELOC,1161
JNE L45 ;IF NOT AT BOTTOM LINE
MOV W[ROWCOL],0326 ;TOP LINE
MOV AL,BOXATTRIB
CALL CURLINE ;CLEAR CURSOR LINE
MOV CURLINELOC,361 ;TOP LINE
MOV CUROWPTR,OFFSET CUROW
JMP PREADKBD
L45:
CMP CURLINELOC,361
JE MODEM ;IF AT TOP LINE
JMP GODOWN
L5:
CMP AL,01B ;ESC
IF E JMP EXIT
L6:
CMP AX,02D00 ;ALT-X
IF E JMP EXIT
L7:
CMP AL,8 ;BACKSPACE
JNE >L8
CMP COL,38
JE JMPREADKBD
DEC COL
CALL MOVCUR
MOV AL,' '
CALL WRITIT
JMP READKBD
L8:
CMP AX,05300 ;DELETE
JNE >L9
MOV AL,' '
CALL WRITIT
JMPREADKBD:
JMP READKBD
L9:
CMP AL,' '
JB JMPREADKBD
CMP AL,07F
JA JMPREADKBD
CMP AL,'a'
JB >L0
CMP AL,'z'
JA >L0
AND AL,0DF ;MAKE IT UPPERCASE
L0:
CALL WRITIT
CMP COL,59
JE JMPREADKBD
INC COL
JMP PREAD2
MODEM:
MOV AX,DS
MOV ES,AX
MOV DS,SCREENSEG ;!
MOV DI,BUF
MOV DX,396
MOV BX,5
L1:
ADD DX,160
MOV SI,DX
MOV CX,22
L2:
MOVSB
INC SI
LOOP L2
DEC BX
JNZ L1
MOV AX,CS
MOV DS,AX
CALL BUF2MEM ;MOV BUF DATA TO PHONE2, ETC
CMP FLAGBYTE,0
JNZ >L3 ;IF .CFG FILE EXISTS
MOV AH,03C ;FUNCTION TO CREATE/TRUNCATE FILE
MOV CX,0 ;FILE ATTRIB
MOV DX,OFFSET CFG
INT 021
MOV HANDLE,AX
L3:
MOV AH,040 ;FUNCTION TO WRITE FILE
MOV BX,HANDLE
MOV CX,110 ;NUMBER OF BYTES TO WRITE
MOV DX,OFFSET BUF
INT 021
;INITIALIZE UART PORT ADDRESSES
MOV AL,COMPORT
SUB AL,'1'
CBW
SHL AX,1 ;MUL 2
MOV SI,AX
MOV AX,040 ;SEGMENT WHERE COM PORT ADDRESS IS
MOV DS,AX ;!
MOV AX,[SI]
MOV CX,CS
MOV DS,CX
OR AX,AX
JNZ GOTPORT ;IF THERE'S AN ADDRESS THERE
JMP EXIT
GOTPORT:
MOV DI,OFFSET TR_BUFFER
MOV CX,7
L1:
STOSW ;INITIALIZE PORT ADDRESSES
INC AX ;NEXT ADDRESS
LOOP L1
MOV AH,0 ;FUNCTION TO CONFIGURE COMM PORT
; MOV AL,00011010xB ;EVEN PARITY, 1 STOP BIT, 7 BITS
MOV AL,3 ;NO PARITY, 1 STOP BIT, 8 BITS
MOV BL,10100000xB ;FOR 2400 BAUD
MOV SI,OFFSET SPEED
CMP W[SI],'3 '
JNE >L2
MOV BL,01000000xB
JMP SHORT >L5
L2:
CMP W[SI],'30'
JNE >L3
MOV BL,01000000xB
JMP SHORT >L5
L3:
CMP W[SI],'21'
JNE >L4
MOV BL,10000000xB
JMP SHORT >L5
L4:
CMP W[SI],'69'
JNE >L5
MOV BL,11100000xB
L5:
OR AL,BL ;MODEM SPEED
MOV DL,B[COMPORT]
SUB DL,'1'
MOV DH,0
INT 014 ;BIOS CONFIGURES COMM PORT
MOV DX,INT_IDENT
; MOV AL,11000001xB ;ENABLE 16550A BUFFER
MOV AL,0 ;DISABLE 16550A BUFFER
OUT DX,AL
;INITIALIZE BUFFERS
MOV CX,OFFSET IN_BUFF
MOV BX,OFFSET IN_BUFF_HEAD
MOV W[BX],CX
MOV W[BX+2],CX ;IN_BUFF_TAIL
MOV W[BX+4],CX ;IN_BUFF_BEGIN
ADD CX,IN_BUFF_SIZE ;8080
MOV W[BX+6],CX ;IN_BUFF_END
MOV BX,OFFSET OUT_BUFF_HEAD
MOV W[BX],CX
MOV W[BX+2],CX
MOV W[BX+4],CX
ADD CX,OUT_BUFF_SIZE
MOV W[BX+6],CX
;ENABLE INTS, MODIFY THE INTERRUPT VECTOR FOR THE COMM PORT, AND SET 8259 MASK
CLI
MOV DX,MODEM_CONTROL
MOV AL,00001011xB
OUT DX,AL ;TURN ON DTR, RTS, & ENABLE INTERRUPTS
STI
CMP B[COMPORT],'1'
JE >L1
MOV AL,11 ;INT VECTOR FOR COMM2
MOV BL,11110111xB ;MASK FOR 8259 COMM2
JMP SHORT >L2
L1:
MOV AL,12 ;INT VECTOR FOR COMM1
MOV BL,11101111xB ;MASK FOR 8259 COMM1
L2:
PUSH AX,BX ;SAVE AL
MOV AH,035 ;FUCTION TO GET INTERRUPT VECTOR
INT 021
MOV INTOFF,BX
MOV INTSEG,ES
MOV AX,CS
MOV ES,AX
POP BX,AX ;GET AL & MASK
MOV AH,025 ;FUNCTION FOR COMM INT VECTOR TO POINT TO INT_COMM
MOV DX,OFFSET INT_COMM;COMM INTERRUPT ROUTINE
INT 021
IN AL,021 ;GET CURRENT 8259 INT MASK
AND AL,BL ;MASK APPROPRIATE BIT
OUT 021,AL ;NEW 8259 MASK
;ENABLE DATA RECEIVED INTERRUPT AND RESET 8250
MOV DX,INT_ENABLE
MOV AL,00000011xB ;ENABLE DATA RECEIVED & THR EMPTY INTERRUPTS
OUT DX,AL
MOV DX,TR_BUFFER ;aka THR
MOV CX,7
L3:
IN AL,DX ;READ UART REGISTERS TO RESET THEM
INC DX
LOOP L3
MOV AX,OUT_BUFF_TAIL
MOV OUT_BUFF_HEAD,AX
MOV AX,IN_BUFF_TAIL
MOV IN_BUFF_HEAD,AX
;CALL COMPUSERVE...
MOV SI,OFFSET INIT
CALL LOAD_STRING ;INITIALIZE MODEM
MOV BX,OFFSET OK
CALL WAITFOR2
MOV ROWCOL,0A00
CALL MOVCUR
MOV AH,9
MOV DX,OFFSET CALLING
INT 021
CALL DELAY
MOV SI,OFFSET PHONENO ;CALL COMPUSERVE
CALL LOAD_STRING
MOV AH,1
INT 016
JZ >L1 ;IF NO KEY PRESSED
MOV AH,0 ;CLEAR KEYBOARD BUFFER
INT 016
JMP MAIN
L1:
MOV BX,OFFSET CONNECT
CALL WAITFOR2
CALL DELAY
MOV SI,OFFSET SENDCR
CALL TRANSMIT
MOV BX,OFFSET HOST
CALL WAITFOR
MOV SI,OFFSET SENDHOST
CALL TRANSMIT
MOV BX,OFFSET USER
CALL WAITFOR
MOV SI,OFFSET SENDUSER
CALL TRANSMIT
MOV BX,OFFSET PASSWORD
CALL WAITFOR
MOV SI,OFFSET SENDPASS
CALL TRANSMIT
DOWNLOADRET:
MOV BX,OFFSET EXCLAIM
CALL WAITFOR
PREKEYINPUT:
MOV DI,BUF
KEYINPUT:
MOV AH,1 ;FUNCTION TO GET KEYBOARD STATUS
INT 016
JNZ CHKBD ;IF KEYBOARD INPUT
CALL GET_BUFF_DATA2
JNC KEYINPUT ;IF NOTHING IN BUFFER
CMP AL,ENQ
IF E JMP DOWNLOAD
AND AL,07F ;STRIP HI BIT (I THINK COMPUSERVE ALWAYS SENDS PARITY)
STOSB ;ADD IT TO STRING IN BUF
CALL WRITE ;WRITE CHAR ON SCREEN
JMP SHORT KEYINPUT
CHKBD:
MOV AH,0 ;FUNCTION TO GET KEYBOARD CHAR
INT 016
GOMANUAL:
CMP AL,0
JZ EXTENDEDKEY ;IF NOT NORMAL CHAR
CMP AL,01B ;ESC
JE EXIT_MANNED
CALL PUT_BUFF_DATA
JMP SHORT KEYINPUT
EXTENDEDKEY:
CMP AH,02D ;ALT-X
JNE KEYINPUT
;Disable the serial port interrupts and reset the 8259 mask
EXIT_MANNED:
MOV DX,INT_ENABLE ;Interrupt enable reg.
MOV AL,0
OUT DX,AL ;Disable all interrupts
CMP B[COMPORT],'1' ;Determine mask bit to change
JZ EM_10
MOV BL,00001000xB ;Mask for 8259 comm2
JMP SHORT EM_20
EM_10:
MOV BL,00010000xB ;Mask for 8259 comm1
EM_20:
IN AL,021 ;Get current 8259 int mask
OR AL,BL ;Set appropriate int bit
OUT 021,AL ;And set new 8259 mask
MOV AL,11 ;Vector for comm2
CMP B[COMPORT],'1' ;Determine INT vector to change
IF E MOV AL,12 ;Vector for comm1
MOV AH,025 ;FUNCTION TO SET INTERRUPT VECTOR
MOV DX,INTOFF
MOV DS,INTSEG ;!
INT 021
MOV AX,CS
MOV DS,AX
CALL DELAY
MOV DX,MODEM_CONTROL
IN AL,DX
AND AL,11111110xB ;TURN DTR OFF
OUT DX,AL
CALL DELAY
MOV DX,MODEM_CONTROL
IN AL,DX
OR AL,1 ;TURN DTR BACK ON
OUT DX,AL
EXIT:
MOV AH,03E ;FUNCTION TO CLOSE FILE
MOV BX,HANDLE
INT 021
CALL CLRSCRN
MOV AX,04C00 ;EXIT TO DOS
INT 021
;*****SUBROUTINES*****
TRANSMIT:
MOV AH,1 ;FUNCTION TO GET KEYBOARD STATUS
INT 016
JNZ PREXIT ;IF ANY KEY PRESSED
;PUT STRING POINTED TO BY SI IN OUTPUT BUFFER
LOAD_STRING:
LODSB
LSLOOP:
CALL PUT_BUFF_DATA
LODSB
CMP AL,0
JNZ LSLOOP ;IF NOT AT END OF STRING
RET
WAITFOR:
MOV DX,OFFSET BUF
WAITLP:
MOV AH,1 ;FUNCTION TO GET KEYBOARD STATUS
INT 016
JNZ PREXIT ;IF KEYBOARD INPUT
MOV DI,DX
PUSH BX
CALL GET_BUFF_DATA2 ;GET INPUT CHAR IN AL
POP BX
JNC WAITLP ;IF NO CHAR IN BUFFER YET
AND AL,07F ;STRIP HI BIT
STOSB ;ADD IT TO STRING IN BUF
PUSH BX
CALL WRITE ;WRITE CHAR ON SCREEN
POP BX
MOV SI,BX ;OFFSET OF STRING TO MATCH
MOV CX,W[SI-2] ;LENGTH OF STRING
MOV DX,DI ;SAVE IT
SUB DI,CX ;START AT BEGINNING OF POSSIBLE MATCH
REPE CMPSB
JNE WAITLP ;IF STRING NOT RECEIVED YET
RET
WAITFOR2:
MOV DX,OFFSET BUF
WAITLP2:
MOV AH,1 ;FUNCTION TO GET KEYBOARD STATUS
INT 016
JNZ PREXIT ;IF KEYBOARD INPUT
MOV DI,DX
PUSH BX
CALL GET_BUFF_DATA2 ;GET INPUT CHAR IN AL
POP BX
JNC WAITLP2 ;IF NO CHAR IN BUFFER YET
AND AL,07F ;STRIP HI BIT
STOSB ;ADD IT TO STRING IN BUF
MOV SI,BX ;OFFSET OF STRING TO MATCH
MOV CX,W[SI-2] ;LENGTH OF STRING
MOV DX,DI ;SAVE IT
SUB DI,CX ;START AT BEGINNING OF POSSIBLE MATCH
REPE CMPSB
JNE WAITLP2 ;IF STRING NOT RECEIVED YET
RET
PREXIT:
POP CX ;RET ADDRESS
MOV AH,0 ;FUNCTION TO GET KEYBOARD INPUT
INT 016
MOV DI,BUF
JMP GOMANUAL
;WRITE TO SCREEN
WRITE:
CMP AL,7
JA NOTBEEP
JB GORET ;DON'T DISPLAY EVERYTHING
MOV AH,0E ;WRITE BEEP
INT 010
GORET:
RET
NOTBEEP:
CMP AL,0D
JNE NOTCR
MOV COL,0
JMP MOVCUR
NOTCR:
CMP AL,0A
JNE NOTLF
CMP ROW,24
JE ATBOT2
INC ROW
JMP MOVCUR
ATBOT2:
MOV CX,AX ;SAVE IT
MOV AL,' '
MOV AH,ATTRIB
MOV ES,SCREENSEG
MOV DS,SCREENSEG ;!
PUSH DI
MOV SI,160
SUB DI,DI
MOV BX,24 ;ROWS TO MOVE UP
SCROLL:
MOV CX,80
REP MOVSW
DEC BX
JNZ SCROLL
MOV CX,80
REP STOSW
POP DI
MOV AX,CS
MOV DS,AX
MOV ES,AX
RET
NOTLF:
CMP AL,8 ;BACKSPACE
JNE NOTBS
SUB COL,2 ;SLIGHTLY TRICK
MOV AL,' '
MOV DX,ROWCOL
INC DL ;ROW
JMP SHORT >L1
NOTBS:
CMP AL,12 ;FORM FEED
JE CLRSCRN
; CMP AL,' '
; JB GORET ;DON'T WRITE EVERYTHING
MOV DX,ROWCOL
L1:
MOV CX,AX ;SAVE IT
MOV ES,SCREENSEG
MOV AX,160
MUL DH ;ROW
PUSH DI
MOV DI,AX
MOV AL,DL ;COL
CBW
SHL AX,1
ADD DI,AX ;SCREEN OFFSET
MOV AX,CX ;GET IT BACK
MOV AH,ATTRIB
STOSW ;PUT CHAR ON SCREEN
POP DI
MOV AX,DS
MOV ES,AX
INC COL
JMP MOVCUR ;INSTEAD OF CALL MOVCUR & RET
CLRSCRN:
MOV AH,ATTRIB
MOV AL,' '
MOV ES,SCREENSEG
PUSH DI
SUB DI,DI
MOV CX,2000
REP STOSW
POP DI
MOV AX,DS
MOV ES,AX
MOV DI,BUF ;RE-INITIALIZE
MOV W[ROWCOL],0
MOVCUR:
MOV AH,2 ;FUNCTION TO MOVE CURSOR
MOV BH,0 ;PAGE
MOV DX,ROWCOL
INT 010
RET
;COMMUNICATIONS INTERRUPT HANDLER
INT_COMM:
STI
PUSH DS,AX,BX,DX
MOV AX,CS
MOV DS,AX
MOV DX,INT_IDENT
IN AL,DX
L1:
CMP AL,2
JE >L3 ;IF TRANSMIT BUFFER EMPTY
;received data, get it and store in buffer
DEC DX ;TO PORT BASE ADDRESS
DEC DX
IN AL,DX ;GET DATA FROM RECEIVE REGISTER
MOV BX,IN_BUFF_TAIL
MOV [BX],AL
INC BX
CMP BX,IN_BUFF_END
JNE >L2
MOV BX,IN_BUFF_BEGIN
L2:
CMP BX,IN_BUFF_HEAD
JE >L7 ;IF BUFFER FULL
MOV IN_BUFF_TAIL,BX
JMP SHORT >L7
;transmit buffer empty, send a byte
L3:
DEC DX ;TO PORT BASE ADDRESS
DEC DX
MOV BX,OUT_BUFF_HEAD
CMP BX,OUT_BUFF_TAIL
JE >L6 ;IF NO DATA IN BUFFER
MOV AL,[BX]
OUT DX,AL
INC BX
CMP BX,OUT_BUFF_END
JNE >L5 ;IF NOT BEYOND END OF BUFFER AREA
MOV BX,OUT_BUFF_BEGIN
L5:
MOV OUT_BUFF_HEAD,BX
JMP SHORT >L7
L6:
MOV B[COMM_INT_STA],0 ;RESET TRANSMITTING DATA FLAG
L7:
INC DX ;POINT TO INT. ID REG.
INC DX
IN AL,DX
TEST AL,1
JZ L1 ;IF REQUEST PENDING
MOV AL,020 ;END OF INTERRUPT
OUT 020,AL
POP DX,BX,AX,DS
IRET
GET_BUFF_DATA:
MOV SI,OFFSET IN_BUFF_HEAD
CLI ;Don't allow interrupts
MOV BX,[SI]
CMP BX,[SI+2] ;Test for data in buffer
JE >L1 ;If the same, no data so exit, carry is already reset
MOV AL,[BX] ;Get the data
INC BX ;Point to data in buffer
CMP BX,[SI+6] ;Beyond end of buffer area?
IF E MOV BX,[SI+4] ;Yes, reset to buffer begin
MOV [SI],BX ;Save new head pointer
STC ;Indicate data is in AL
L1:
STI ;Enable interrupts
JNC GET_BUFF_DATA
RET
GET_BUFF_DATA2:
MOV SI,OFFSET IN_BUFF_HEAD
CLI ;Don't allow interrupts
MOV BX,[SI]
CMP BX,[SI+2] ;Test for data in buffer
JE >L1 ;If the same, no data so exit, carry is already reset
MOV AL,[BX] ;Get the data
INC BX ;Point to data in buffer
CMP BX,[SI+6] ;Beyond end of buffer area?
IF E MOV BX,[SI+4] ;Yes, reset to buffer begin
MOV [SI],BX ;Save new head pointer
STC ;Indicate data is in AL
L1:
STI ;Enable interrupts
RET
PUT_BUFF_DATA:
PUSH SI,DI
MOV SI,OFFSET OUT_BUFF_HEAD ;Point to output buffer
CLI ;Don't allow interrupts
MOV BX,[SI+2] ;BUFFER TAIL POINTER
MOV DI,BX
INC BX ;TO MOVE BUFFER TAIL POINTER
CMP BX,[SI+6]
IF E MOV BX,[SI+4] ;IF AT END OF BUFFER, PUT AT BEGINNING OF BUFFER
CMP BX,[SI]
JE >L1 ;IF POTENTIAL BUFFER TAIL LOC = BUFFER HEAD LOC
MOV [DI],AL ;STORE DATA AT OLD BUFFER TAIL
MOV [SI+2],BX ;UPDATE BUFFER TAIL POINTER
STC ;INDICATE DATA STORED OK
L1:
PUSHF ;Save the flags
CMP B[COMM_INT_STA],1 ;Transmit int. running?
JE >L2 ;Yes, so exit
MOV B[COMM_INT_STA],1 ;Set transmitting data flag
PUSH AX
MOV BX,[SI] ;Get the buffer head pointer
MOV AL,[BX] ;Get the data
INC BX ;Point to data in buffer
CMP BX,[SI+6] ;Beyond end of buffer area?
IF E MOV BX,[SI+4] ;Yes, reset to buffer begin
MOV [SI],BX ;Save new head pointer
MOV DX,TR_BUFFER ;Get port base address
OUT DX,AL ;Send the data out the port
POP AX
L2:
STI ;Enable interrupts
POPF
POP DI,SI
JNC PUT_BUFF_DATA
RET
WRITIT:
MOV AH,0A ;FUNCTION TO WRITE CHAR AT CURSOR
MOV BH,0 ;PAGE NUMBER
MOV CX,1 ;NUMBER OF REPETITIONS
INT 010
RET
MAKECURLINE:
MOV AL,CURATTRIB
CURLINE:
MOV DI,CURLINELOC
MOV CX,40
L1:
STOSB
INC DI
LOOP L1
RET
DownloadMenu:
db '╔══════════════════════════╗'
db '║ Downloading ║'
db '║ (1,024 Bytes/Block) ║'
db '║ ║'
db '║ Blocks Received: 00 ║'
db '║ Elapsed Time: 00:00 ║'
db '╚══════════════════════════╝'
DownloadName db 11 dup(?)
FileSize dw ?
TimerCount dw ? ;for elapsed time
Blocks dw 0
LastDI dw ?
LastES dw ?
NAKCount db 0
;COMPUSERVE B+ PROTOCOL...
;DLE,'B',Sequence,Type,Body,ETX,Checksum
ETX equ 03
ENQ equ 05
DLE equ 010
NAK equ 015
;XOFF equ 011 ;& 091
;XON equ 013 ;& 093
;Quoted characters: 03,05,010,011,013,015,091,093
TheirSeq db ?
Initialize db DLE,'+','+',DLE,'0'
LeadIn db DLE,'B'
MySequence db '0'
MyParams db '+'
; WS WR BS CM DQ TL Q1 Q2 Q3 Q4 Q5 Q6 Q7 Q8 DR UR FI
db 1, 1, 8, 0, 3, 0, 014, 0, 0D4, 0, 0, 0, 050, 0, 0, 0, 0
db ETX
UnQuote MACRO
cmp al,DLE
jne >L9 ;if not quoted
call Get_Buff_Data
cmp al,060
jb >L8
and al,01F ;clear bits 7,6,5
or al,080 ;set bit 7
jmp short >L9
L8:
and al,01F ;un-quote it
L9:
#EM
PutInChecksum MACRO
rol ah,1
add ah,al
adc ah,0
#EM
DOWNLOAD:
; cli
; mov al,3 ;8 bits, no parity, 1 stop bit
; mov dx,Line_Control
; out dx,al
; sti
mov MySequence,'0' ;initialize
mov Blocks,0
mov NAKCount,0
SendInit:
mov si,offset Initialize
mov cx,5
L1:
lodsb
call Put_Buff_Data
loop L1
GetParameters:
mov ah,0 ;initialize for Checksum
call Get_Buff_Data
cmp al,ENQ
je SendInit
cmp al,DLE
jne GetParameters
call Get_Buff_Data
cmp al,'B'
jne GetParameters
call Get_Buff_Data
mov TheirSeq,al
PutInChecksum
call Get_Buff_Data
cmp al,'+'
jne GetParameters
PutInChecksum
TheirParamLP:
call Get_Buff_Data
cmp al,ETX
je >L1 ;if at end
UnQuote ;un-quote all chars 0-01F & 080-09F
PutInChecksum
jmp short TheirParamLP
L1:
PutInChecksum ;ETX
call Get_Buff_Data
UnQuote
cmp al,ah
if ne jmp Error ;if Checksum not right
;clear screen & put download window on screen
call clrscrn
mov w[rowcol],01900 ;move cursor off screen
call movcur
mov es,ScreenSeg
mov al,boxattrib
mov si,offset DownloadMenu
mov dx,1330
mov bx,7
L1:
mov di,dx
mov cx,28
L2:
movsb
stosb
loop L2
es mov w[di],0db ;side shadow
add dx,160
dec bx
jnz L1
mov ah,attrib
mov al,' '
es mov w[1386],ax ;erase part of shadow
mov di,dx
add di,2
mov ax,0db ;bottom shadow
mov cx,28
rep stosw
mov ax,ds
mov es,ax
;get initial timer count
mov cx,040
mov ds,cx ;!
mov ax,[06c] ;timer count
mov cx,cs
mov ds,cx
mov TimerCount,ax
mov al,DLE ;positive acknowledgment
call Put_Buff_Data
mov al,TheirSeq
call Put_Buff_Data
mov cx,2 ;do following routine twice (B+ PROTOCOL...)
SendMyParams:
inc MySequence
mov ah,0 ;initialize Checksum
mov si,offset LeadIn ;DLE,'B'
lodsb
call Put_Buff_Data
lodsb
call Put_Buff_Data
SendParams:
lodsb ;Sequence,'+',MyParams,ETX
PutInChecksum
cmp al,ETX
je ItsETX
cmp al,01F ;Checksum
jbe LowQuote
cmp al,080
jb NoQuote
cmp al,09F
ja NoQuote
HiQuote:
push ax
mov al,DLE
call Put_Buff_Data
pop ax
and al,01F
add al,060 ;quote it
call Put_Buff_Data
jmp short SendParams
LowQuote:
push ax
mov al,DLE
call Put_Buff_Data
pop ax
add al,040 ;quote it
NoQuote:
call Put_Buff_Data
jmp short SendParams
ItsETX:
call Put_Buff_Data ;ETX
cmp ah,01F ;Checksum
jbe LowQuote2
mov al,ah
cmp al,080
jb NoQuote2
cmp al,09F
ja NoQuote2
HiQuote2:
mov al,DLE
call Put_Buff_Data
mov al,ah ;Checksum
and al,01F
add al,060 ;quote it
jmp short NoQuote2
LowQuote2:
mov al,DLE
call Put_Buff_Data
mov al,ah ;Checksum
add al,040 ;quote it
NoQuote2:
call Put_Buff_Data
;get ACK
call Get_Buff_Data
cmp al,DLE
if ne jmp Error
call Get_Buff_Data
cmp al,MySequence
if ne jmp Error
dec cx
if nz jmp SendMyParams
;***NOW GET DATA PACKETS***
sub di,di ;to hold downloaded file
mov es,NextSeg
GetPacket:
mov LastDI,di ;save it for SendNAK
mov LastES,es ;ditto
call Get_Buff_Data ;DLE
cmp al,ENQ
je jmpError
cmp al,NAK
je jmpError
cmp al,DLE
jne jmpError
call Get_Buff_Data ;'B'
cmp al,';'
je GetPacket ;if Wait
cmp al,'B'
jne GetPacket
call Get_Buff_Data ;Sequence
mov TheirSeq,al
mov ah,al ;initialize Checksum
call Get_Buff_Data ;Type
PutInChecksum
cmp al,'N'
je DataLoop
cmp al,'T'
if e jmp GotT
cmp al,'F'
jne jmpError
jmp GotF
jmpError:
jmp Error
DataLoop: ;THE BIG LOOP!!!
call Get_Buff_Data
cmp al,ETX
je GotETX ;if end of packet
cmp al,DLE
je IfQuoted
rol ah,1
add ah,al ;put in Checksum
adc ah,0
stosb ;save data in buf
or di,di
jnz DataLoop
mov cx,es
add cx,01000
mov es,cx
jmp short DataLoop
IfQuoted:
call Get_Buff_Data
cmp al,060
jb >L1
and al,01F ;clear bits 7,6,5
or al,080 ;set bit 7
rol ah,1
add ah,al
adc ah,0
stosb ;save data in buf
or di,di
jnz DataLoop
mov cx,es
add cx,01000
mov es,cx
jmp short DataLoop
L1:
and al,01F ;un-quote it
rol ah,1
add ah,al
adc ah,0
stosb ;save data in buf
or di,di
jnz DataLoop
mov cx,es
add cx,01000
mov es,cx
jmp short DataLoop
GotETX:
PutInChecksum ;ETX
call Get_Buff_Data ;Checksum
UnQuote
;show elapsed time
ElapsedTime:
push es
mov es,ScreenSeg
push ax
mov ax,040
mov ds,ax ;!
mov ax,w[06c] ;timer count
mov cx,cs
mov ds,cx
sub ax,TimerCount
sub dx,dx
mov cx,10
mul cx
mov cx,182
div cx ;div 18.2
sub dx,dx
mov cx,60
div cx ;minutes in ax & seconds in dx
aam
add ax,03030
es mov b[2166],ah
es mov b[2168],al
mov ax,dx
aam
add ax,03030
es mov b[2172],ah
es mov b[2174],al
NoCount:
pop ax
cmp al,ah
je ShowBlocks ;if Checksum is okay
pop es
jmp SendNAK
;show blocks received
ShowBlocks:
push di
inc Blocks
mov ax,Blocks
mov di,2012
sub dx,dx
div w[Hundred]
or ax,ax
jz >L1
add al,'0'
es mov b[di],al
add di,2
L1:
mov ax,dx ;remainder
aam
or ax,03030
xchg al,ah
stosb
inc di
mov al,ah
stosb
pop di,es
;send ACK
mov al,DLE
call Put_Buff_Data
mov al,TheirSeq
call Put_Buff_Data
jmp GetPacket
SendNAK:
mov ax,0e07
int 010
inc NAKCount
cmp NAKCount,5
if e jmp Error
mov al,NAK
call Put_Buff_Data
call Get_Buff_Data ;ENQ
call Get_Buff_Data ;ENQ
mov al,DLE
call Put_Buff_Data ;Positive ACK
mov al,TheirSeq
call Put_Buff_Data
mov al,DLE
call Put_Buff_Data
mov al,TheirSeq
call Put_Buff_Data
mov di,LastDI
jmp GetPacket
GotT:
call Get_Buff_Data
cmp al,'D' ;download
je DownloadType
cmp al,'C' ;close (end of download)
if ne jmp Error
mov ax,0e07 ;beep
int 010
L1:
call Get_Buff_Data
cmp al,ENQ
if e jmp DLExit
cmp al,ETX
jne L1 ;we only care about the 'C'
call Get_Buff_Data ;Checksum
cmp al,DLE
if ne jmp DLExit
call Get_Buff_Data
jmp DLExit
DownloadType:
PutInChecksum
call Get_Buff_Data
PutInChecksum
cmp al,'B'
jne Error ;should be a binary file
push di,es
mov cx,ds
mov es,cx
mov di,offset DownloadName
GetName:
call Get_Buff_Data
cmp al,ETX
je GotName
PutInChecksum
stosb
jmp short GetName
GotName:
mov es,ScreenSeg
mov di,1522
mov si,offset DownloadName
mov cx,10
L1:
movsb
inc di
loop L1
pop es,di
PutInChecksum ;ETX
call Get_Buff_Data ;Checksum
UnQuote
cmp al,ah
if ne jmp SendNAK ;if Checksum not right
;send ACK
mov al,DLE
call Put_Buff_Data
mov al,TheirSeq
call Put_Buff_Data
jmp GetPacket
GotF:
Error:
mov ax,0e07 ;beep
int 010
mov si,offset Initialize
mov cx,2
L1:
lodsb
call Put_Buff_Data
loop L1
call Get_Buff_Data ;ENQ
mov si,offset Initialize
mov cx,5
L2:
lodsb
call Put_Buff_Data
loop L2
jmp short DLExit2
DLExit:
mov al,DLE
call Put_Buff_Data
mov al,TheirSeq
call Put_Buff_Data
;save data in file
mov FileSize,di
mov ah,03C ;function to create/truncate file
sub cx,cx ;file attrib
mov dx,offset DownloadName
int 021
mov bx,ax ;handle
mov dx,NextSeg ;first segment
mov bp,es
sub bp,dx
mov cl,4
rol bp,cl ;number of segments
mov ax,FileSize ;size of last segment
Writelp2:
mov TempStorage,ax
mov cx,0FFF0
or bp,bp
if z mov cx,ax
mov ds,dx ;!
push dx
sub dx,dx
mov ah,040 ;function to write file
int 021
mov dx,cs
mov ds,dx
pop dx
add dx,0FFF
jc Writexit ;if more than 1 meg
or ax,ax
jz Writexit ;if disk full
mov ax,TempStorage
sub ax,0FFF0
sbb bp,0
jns Writelp2
Writexit:
mov ah,03E ;function to close file
int 021
DLExit2:
; cli
; mov al,00011010xB ;7 bits, even parity, 1 stop bit
; mov dx,Line_Control
; out dx,al
; sti
mov w[rowcol],01000 ;row 16
call movcur
L1:
mov ah,1
int 016
jz >L2 ;if no key pressed
mov ah,0
int 016 ;get rid of any keyboard input
jmp short L1
L2:
jmp DownloadRet
;DELAY, USING INT 015 EVENT WAIT, OR LOOP
DELAY:
MOV BX,OFFSET FLAGBYTE
MOV B[BX],0
MOV CX,8 ;HIGH COUNT
SUB DX,DX ;LOW COUNT
MOV AX,08300
INT 015
JC >L1 ;IF FUNCTION DOESN'T WORK ON THIS COMPUTER
L0:
TEST B[BX],080
JZ L0 ;LOOP UNTIL HIGH BIT IS SET
RET
L1:
MOV CX,0FFFF
L2:
MOV BX,8
L3:
DEC BX
JNZ L3
LOOP L2
RET
;MOVE CONFIG DATA FROM BUF TO PHONE2, SENDUSER, & SENDPASS
BUF2MEM:
MOV BX,OFFSET BUF
MOV SI,BX
MOV DI,OFFSET PHONE2
MOV CX,22
L1:
LODSB
CMP AL,' '
JE >L3 ;AT END OF NUMBER
CMP AL,'-'
JE >L2
CMP AL,'('
JE >L2
CMP AL,')'
JE >L2
STOSB
L2:
LOOP L1
L3:
MOV W[DI],0D ;0D,0
ADD BX,22
MOV SI,BX
MOV DI,OFFSET SENDUSER
MOV CX,22
L4:
LODSB
CMP AL,' '
JE >L5
STOSB
LOOP L4
L5:
MOV W[DI],0D
ADD BX,22
MOV SI,BX
MOV DI,OFFSET SENDPASS
MOV CX,22
L6:
LODSB
CMP AL,' '
JE >L7
STOSB
LOOP L6
L7:
MOV W[DI],0D
ADD BX,22
MOV SI,BX
MOV DI,OFFSET SPEED
MOV CX,4
REP MOVSB
ADD BX,22
MOV SI,BX
MOV DI,OFFSET COMPORT
MOVSB
RET
COMMENT @
;FOLLOWING IS A TEMPLATE FOR USING CRC INSTEAD OF CHECKSUM
CRC_TABLE:
DW 00000, 01021, 02042, 03063, 04084, 050A5, 060C6, 070E7
DW 08108, 09129, 0A14A, 0B16B, 0C18C, 0D1AD, 0E1CE, 0F1EF
DW 01231, 00210, 03273, 02252, 052B5, 04294, 072F7, 062D6
DW 09339, 08318, 0B37B, 0A35A, 0D3BD, 0C39C, 0F3FF, 0E3DE
DW 02462, 03443, 00420, 01401, 064E6, 074C7, 044A4, 05485
DW 0A56A, 0B54B, 08528, 09509, 0E5EE, 0F5CF, 0C5AC, 0D58D
DW 03653, 02672, 01611, 00630, 076D7, 066F6, 05695, 046B4
DW 0B75B, 0A77A, 09719, 08738, 0F7DF, 0E7FE, 0D79D, 0C7BC
DW 048C4, 058E5, 06886, 078A7, 00840, 01861, 02802, 03823
DW 0C9CC, 0D9ED, 0E98E, 0F9AF, 08948, 09969, 0A90A, 0B92B
DW 05AF5, 04AD4, 07AB7, 06A96, 01A71, 00A50, 03A33, 02A12
DW 0DBFD, 0CBDC, 0FBBF, 0EB9E, 09B79, 08B58, 0BB3B, 0AB1A
DW 06CA6, 07C87, 04CE4, 05CC5, 02C22, 03C03, 00C60, 01C41
DW 0EDAE, 0FD8F, 0CDEC, 0DDCD, 0AD2A, 0BD0B, 08D68, 09D49
DW 07E97, 06EB6, 05ED5, 04EF4, 03E13, 02E32, 01E51, 00E70
DW 0FF9F, 0EFBE, 0DFDD, 0CFFC, 0BF1B, 0AF3A, 09F59, 08F78
DW 09188, 081A9, 0B1CA, 0A1EB, 0D10C, 0C12D, 0F14E, 0E16F
DW 01080, 000A1, 030C2, 020E3, 05004, 04025, 07046, 06067
DW 083B9, 09398, 0A3FB, 0B3DA, 0C33D, 0D31C, 0E37F, 0F35E
DW 002B1, 01290, 022F3, 032D2, 04235, 05214, 06277, 07256
DW 0B5EA, 0A5CB, 095A8, 08589, 0F56E, 0E54F, 0D52C, 0C50D
DW 034E2, 024C3, 014A0, 00481, 07466, 06447, 05424, 04405
DW 0A7DB, 0B7FA, 08799, 097B8, 0E75F, 0F77E, 0C71D, 0D73C
DW 026D3, 036F2, 00691, 016B0, 06657, 07676, 04615, 05634
DW 0D94C, 0C96D, 0F90E, 0E92F, 099C8, 089E9, 0B98A, 0A9AB
DW 05844, 04865, 07806, 06827, 018C0, 008E1, 03882, 028A3
DW 0CB7D, 0DB5C, 0EB3F, 0FB1E, 08BF9, 09BD8, 0ABBB, 0BB9A
DW 04A75, 05A54, 06A37, 07A16, 00AF1, 01AD0, 02AB3, 03A92
DW 0FD2E, 0ED0F, 0DD6C, 0CD4D, 0BDAA, 0AD8B, 09DE8, 08DC9
DW 07C26, 06C07, 05C64, 04C45, 03CA2, 02C83, 01CE0, 00CC1
DW 0EF1F, 0FF3E, 0CF5D, 0DF7C, 0AF9B, 0BFBA, 08FD9, 09FF8
DW 06E17, 07E36, 04E55, 05E74, 02E93, 03EB2, 00ED1, 01EF0
CRC DW 0FFFF ;01500
VALUE DB '3','T','D','B','PISLCC.L15',3 ;DLE,055,DLE,040
;crc = table [((crc shr 8) xor (value)) and $ff] xor (crc shl 8)
GETCRC:
MOV AX,CRC
MOV SI,OFFSET VALUE
MOV CX,15
L1:
MOV DX,AX
MOV AL,AH
MOV AH,0
MOV DH,DL
MOV DL,AH
XOR AL,[SI]
INC SI
MOV BX,AX
SHL BX,1
MOV AX,CRC_TABLE[BX]
XOR AX,DX
LOOP L1
MOV CRC,AX
RET
@
IN_BUFF EQU $
IN_BUFF_SIZE EQU 04000
OUT_BUFF_SIZE EQU 04000
OUT_BUFF EQU IN_BUFF + IN_BUFF_SIZE
BUF EQU OUT_BUFF + OUT_BUFF_SIZE